package com.gzsxy.esjy.redis.config;

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;

import com.gzsxy.esjy.redis.cache.GosuncnCacheHandler;
import com.gzsxy.esjy.redis.common.ThreadLocalProxyHolder;
import com.gzsxy.esjy.redis.extend.ICacheHashOneDay;
import com.gzsxy.esjy.redis.extend.RedisLock;
import com.gzsxy.esjy.redis.extend.RedisService;
import com.gzsxy.esjy.redis.extend.StringRedisTemplate;
import com.gzsxy.esjy.redis.extend.impl.CacheHashOneDay;
import com.gzsxy.esjy.redis.extend.impl.DefaultRedisServiceImpl;
import com.gzsxy.esjy.redis.extend.impl.RedisDistributedLock;
import com.gzsxy.esjy.redis.user.ISystemUser;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.time.Duration;
import java.util.concurrent.ThreadPoolExecutor;


@Configuration
@EnableCaching  //启用缓存功能
public class StarterConfiguration {


    /**
     * 我们自定义一个 RedisTemplate，设置序列化器，这样我们可以很方便的操作实例对象。
     * 否则redis自动使用对象的jdk序列化 获取不到 key value
     */
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) {


        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(factory);
        //为了自己开发开发方便，一般直接使用<String, Serializable> 类型
//        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        //value序列化
//        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //key序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        template.afterPropertiesSet();

        return template;
    }


    //修改Redis配置类  缓存注解
    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory connectionFactory){
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //过期时间600秒
                .entryTtl(Duration.ofSeconds(600))
                //配置序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
        return cacheManager;

    }


    //redis方法封装类注入bean
    @Bean
    @ConditionalOnMissingBean
    public RedisService redisService() {
        DefaultRedisServiceImpl service = new DefaultRedisServiceImpl();
        return service;
    }

    //redis方法封装类注入bean
    @Bean
    @ConditionalOnMissingBean
    public RedisLock redisLock() {
        RedisDistributedLock redisLock = new RedisDistributedLock();
        return redisLock;
    }

    @Bean
    @ConditionalOnMissingBean
    public ICacheHashOneDay cacheHashOneDay(RedisService redisService) {
        return new CacheHashOneDay(redisService);
    }

    //用于定义了@GosunCache注解，进行AOP切面标识
    @Bean
    @ConditionalOnProperty(name = "gosuncn.cache.enable", havingValue = "true", matchIfMissing = true)
    public GosuncnCacheHandler gosuncnCacheHandler(RedisService redisService) {
        return new GosuncnCacheHandler(redisService);
    }


    //注册代理对象实例
    //ConditionalOnMissingBean  当你的bean被注册之后，如果而注册相同类型的bean，就不会成功，它会保证你的bean只有一个，即你的实例只有一个
    @Bean
    @ConditionalOnMissingBean
    public ISystemUser iSystemUser() {
        return ThreadLocalProxyHolder.getContextHolderProxy(ISystemUser.class);
    }



    /**
     * @description: 线程池定义
     * @param
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //线程池大小
        executor.setCorePoolSize(6);
        //队列程度
        executor.setQueueCapacity(1000);
        //最大核心线程数
        executor.setMaxPoolSize(30);
        //线程空闲时间
        executor.setKeepAliveSeconds(1000);
        //线程前缀名称
        executor.setThreadNamePrefix("esjy-thread-executor-");
        //配置拒绝策略(但队列满了不处理，抛出异常)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //初始化
        executor.initialize();
        return executor;
    }

}
